#! /usr/bin/ruby

class Interpolation
	
	def initialize
		function_vals=Array.[](:function_1,:function_2,:function_3,:function_4)

		print "Enter 1 for Sin(x^2),\nEnter 2 for e^(Sin(x)),\nEnter 3 for 0.2/((x-3.2)**2+0.04)\n:"; function = gets
		print "Enter a value for x: "; x = gets
		print "Enter a value for the start of the range: "; start_x = gets
		print "Enter a value for the end of the range: "; end_x = gets
		print "Enter the number of division points: "; division_points = gets

		build_conditions(function_vals[function.to_i-1],x.to_f,start_x.to_f,end_x.to_f,division_points.to_f)	
	end

	def build_conditions(function,x,start_x,end_x,division_points)	
		x_values = Array.new
		steps=(end_x-start_x)/division_points
		start_x.step(end_x,steps) { |f| x_values << f }
	
		0.upto(x_values.length-1) do |x_step|
			if (x_values[x_step]< x && x < x_values[x_step+1])
				get_data(x_values[x_step],x_values[x_step+1],x,function,x_values)
			elsif (x_values[x_step]==x)
				get_data(x_values[x_step],x_values[x_step+1],x,function,x_values)
			end
		end

	end


	def get_data(x_i,x_f,x,function,x_values)
		val_initial = self.send(function,x_i)
		val_final = self.send(function,x_f)
		x_calc = self.send(function,x)

		linear_val=linear_approx(val_initial,val_final,x_i,x_f,x)
		lagrange_val=lagrange_approx(x_values,x,0,function)
		
		p "Linear Approximation"
		p linear_val
		p x_calc
		p (1-(linear_val/x_calc))*100
		p "Lagrange Approximation"
		p lagrange_val
		p x_calc
		p (1-(lagrange_val/x_calc))*100
	end

	def linear_approx(val_initial,val_final,x_i,x_f,x)
		return ((val_final-val_initial)/(x_f-x_i))*(x-x_i)+val_initial
	end

	def lagrange_approx(x_values,x,k,function)
		if k<x_values.length
			return p_of_k(x_values,x,k,0)*self.send(function,x_values[k]) + lagrange_approx(x_values,x,k+1,function)
		else
			return 0
		end
	end

	def p_of_k(x_values,x,k,i)
		if k==i
			return p_of_k(x_values,x,k,i+1)
		elsif i<x_values.length
			return ((x-x_values[i])/(x_values[k]-x_values[i]))*p_of_k(x_values,x,k,i+1)
		else
			return 1
		end
	end

	def function_1(x)
		return Math.sin(x**2)
	end

	def function_2(x)
		return Math.exp(Math.sin(x))
	end

	def function_3(x)
		return 0.2/((x-3.2)**2+0.04)
	end
	
	def function_4(x)
		return x**3-10*x**2+4*x+6
	end
end

Interpolation.new
